Skip to content

test(cli): mask comments in the nightly-tier readers of this package's own source, and derive the pins that bound a spelling - #18924

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-18520-nightly-pin-source-readers
Sep 18, 2026
Merged

os-support-ai merged 2 commits into
mainfrom
claude/issue-18520-nightly-pin-source-readers

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes #18520

Clause-②: no

The nightly-tier test files under packages/cli/test/ that read this package's own source
TEXT now read it through the shared mask (scripts/js-comment-mask.mjs), and the pins that
bound a byte-exact SPELLING now bind a property derived from the source instead. Every file
was judged on its own; the table below gives the rung and the reason per file.

The population, re-derived — no number inherited

Predicate, stated: a file under packages/cli/test/ whose NAME puts it in a nightly tier
(scripts/nightly-tiers.mjs — *.e2e.test.* / *.live.test.*, and nothing else selects a
tier), which READS this package's own source text at test time, directly or through a helper
under test/helpers/ it imports. Evaluated over each file's local import closure, on MASKED
text, so a read one module away still counts and a path named only in prose does not.

predicate count measured at
card's: test/*.e2e.test.ts containing readFileSync 26 reproduces exactly
card's: of those, importing the shared mask 3 reproduces exactly — serve-port-readback, published-entry-stderr-nonblocking, run-dev-stderr-nonblocking
claim's: grep -rl readFileSync test/*.e2e.test.ts | xargs grep -l 'src/' 20 reproduces exactly
mine (above) — nightly-tier readers of this package's own source 15 12 raw, 3 already masked

⭐ 20 and 15 are not a contradiction — they are two predicates, and the delta is readable
both ways.
Eight files are in the claim's 20 and not in mine, three are in mine and not in
its 20:

  • prose only — lint-eval-generator-load-envelope matches src/ in a docblock sentence
    and reads /definitely/not/here.json. This is the false positive the dispatch predicted.
  • a temp fixture's src/, not ours — build-docs-step-count, build-multi-package-artifact,
    generate-skill, serve-publishes-bound-port create src/docs or src/skills inside a
    scratch project and read dist/objectstack.json back.
  • another package's source — scaffold-emission-policy reads packages/create-objectstack's
    template package.json. JSON carries no comments, so no rung applies.
  • own source, but bin/ not src/ — published-entry-stderr-nonblocking (already masked)
    and run-dev-unbuilt-workspace (raw). Both read a hand-written published entry; the second is
    in this PR, the first was already correct.
  • missed by the claim's grep, found by mine — config-miss-stdout-purity reads
    src/commands through test/helpers/config-miss-family.ts and never spells src/ itself;
    invocation-loudness and serve-host-fallback-base DO spell ../src/... but never read it
    as text — they symlink/execFile it, so they are readers of a module, not of prose.

Rung per file

file reads rung what changed, and why that rung
build-json-failure-conversions.e2e.test.ts src/commands/compile.ts 3 only Masked. Its indexOf ORDER block (declAt / tryAt / loadAt / normalizeAt) is the #17633 shape verbatim — raw positions over a file whose docblocks name await loadConfig(. ⛔ The six frozen integers are card #18894's and are untouched here.
build-json-failure-warnings.e2e.test.ts src/commands/compile.ts 3 only Masked, same fence — integers untouched.
cloud-login-json-ndjson.e2e.test.ts src/commands/cloud/login.ts 3 + 2 Masked; and the pin that subtracted ONE byte-exact line from the emitJson( hits now partitions the call sites against emitRecord's own brace-matched body: outside must be empty, inside must not be.
login-json-ndjson.e2e.test.ts src/commands/login.ts 3 + 2 Same conversion, same reason.
login-json-noninteractive.e2e.test.ts src/commands/login.ts 3 Masked only. Its rl.question( filter already binds a SHAPE (does the line carry the abort signal), not a spelling — rung 2 has nothing to convert.
json-stdout-purity.e2e.test.ts src/commands/** 3 + 2 Masked; and toHaveLength(10) demoted to a floor. The line above it already binds the SET against the map a sibling nightly file drives, so the integer was a second frozen copy of one fact. It stays as a floor because it is the only guard on the vacuum both sides share.
config-miss-stdout-purity.e2e.test.ts src/commands/** via helper 3 ⭐ No edit in this file — its reader lives in test/helpers/config-miss-family.ts, which this PR masks once for both consumers.
test/helpers/config-miss-family.ts src/commands/** 3 Masked. Both discovery halves are regexes over command source and both are satisfiable by prose: a docblock naming json: Flags.boolean( beside a utils/config.js import invents a direct member; a commented-out export default class X extends Y invents an alias.
diff-usage-error-stream.e2e.test.ts src/commands/** 3 Masked. This scan decides by LINE POSITION — writers above the first flags.json read — which is the print-ORDER failure that opened this card. Its toBeGreaterThan(10) population control was already a floor.
run-dev-unbuilt-workspace.e2e.test.ts bin/run-dev.js 3 Masked. exec takes the FIRST match, so a docblock recording the old STDERR_DRAIN_STALL_MS would be read as the shim's bound. Its sibling over the other published entry already masks; this makes the pair consistent.
serve-app-anchored-optional-import.e2e.test.ts src/commands/serve.ts 1 + 2 + 3 See below — five byte-exact statement pins, rewritten.
validate-json-failure-conversions.e2e.test.ts src/commands/validate.ts 3 Masked, and the paragraph that recorded the opposite decision is corrected rather than left false.
validate-json-failure-warnings.e2e.test.ts src/commands/validate.ts 3 Same.
serve-port-readback · published-entry-stderr-nonblocking · run-dev-stderr-nonblocking own source — Already masked. Untouched.

Rung 1 — where it applied, and where it did NOT

Rung 1 permits DELETING a nightly assertion when a per-PR sibling already binds the same
thing. I searched for a sibling for every byte-exact subject in this population and opened
the one I found:

  • ✅ Applied once. serve-app-anchored-optional-import bound
    function importFromHost(specifier: string, hostRoot: string = servedAppRootOrCwd()) — an
    argument LIST, the feat(cli): objectstack dev --cert/--key terminates TLS in the dev process, and the canonical origin follows the listener #17725 shape exactly. src/commands/serve-cluster-host-resolution.test.ts
    is queue-tier (its name carries no .e2e, so nightly-tiers.mjs leaves it in the per-PR run)
    and binds that function's EXISTENCE, its module scope and its uniqueness. So this PR does not
    re-pin any of that here; what it keeps, because the sibling does not bind it, is the DEFAULT —
    read off the paren-matched parameter list.
  • ⛔ Did not apply anywhere else, and this is a measurement. anchorServedApp and
    servedAppRootOrCwd appear in no other test in the package. The login emitter contract
    (emitRecord) appears in no queue-tier test at all. For warningsSoFar, the queue-tier
    test/truncation-remainder-notices.test.ts binds 'warnings: warningsSoFar(),' in
    compile.ts — the CALL SITE, not the declaration and not the spread ORDER these files pin,
    and for validate.ts it binds different payload keys entirely. Not the same thing, so
    nothing was deleted on its account.

serve-app-anchored-optional-import in detail

Five toContain/toMatch pins over whole statements of serve.ts, in a file only the nightly
tier collects. Each now binds what it was written for:

was is
toContain('const { configPath: absolutePath, configExists } = anchorServedApp(args.config!);') exactly ONE anchorServedApp( call site (the declaration excluded by the same function lookbehind the per-PR sibling uses), and its ARGUMENT is args.config!. The destructured local names are deliberately no longer bound.
not.toMatch(/const absolutePath = path\.resolve\(process\.cwd\(\), args\.config!\)/) the same negative as a SHAPE: path.resolve(process.cwd(), args.config with whitespace tolerated. A negative pin on one exact spelling passes for every respelling of the defect.
toContain('function importFromHost(specifier: string, hostRoot: string = servedAppRootOrCwd())') the hostRoot parameter's DEFAULT, read off the paren-matched parameter list. A third parameter or a renamed specifier no longer reddens it.
toContain('const hostRoot = servedAppRootOrCwd();') and toContain('const root = hostRoot ?? servedAppRootOrCwd();') a partition over every const/let host-root binding: at least two exist, and none may be bound without resolving through servedAppRootOrCwd().
toMatch(/^function servedAppRootOrCwd\(\): string \{$/m) exactly one MODULE-SCOPE function servedAppRootOrCwd(, never indented, never a const/let/var. The return-type annotation and the brace are not the defect.

What the mask changed TODAY: nothing — and that is the measurement

Every converted reader was evaluated raw and masked over the same tree, and every verdict is
identical. Masking is therefore behaviour-preserving now and protective later — it did not
launder a stale pin green:

SAME  json-stdout-purity/discoverFamily        (the same command ids)
SAME  config-miss-family/discover              (the same 10 ids)
SAME  diff-usage/offenders                   = []
SAME  diff-usage/withJson count              = 28
SAME  emitJson call sites — login.ts         = 1      cloud/login.ts = 1
SAME  rl.question without signal — login.ts  = []
SAME  payloadLiterals — validate.ts          = 7      compile.ts = 11
SAME  order indexes — validate.ts / compile.ts       (declAt/tryAt/loadAt/normalizeAt)
SAME  serve.ts anchorServedApp / servedAppRootOrCwd sites
SAME  run-dev STDERR_DRAIN_STALL_MS          = "15_000"

⛔ scripts/check-comment-mask-adoption.mjs is green before and after and its ledger is
unchanged at 14 rows — because none of these twelve files ever carried a private stripper.
They carried NO masking at all, which is the blind spot the card names and the gate documents.
This PR adds no private stripper; every file imports the shared module.

Ablations

Each is a script with trap restore on EXIT INT TERM, absolute paths, an on-disk occurrence
count proving the mutation landed, exit codes captured BEFORE any pipe, and a restore proven by
git hash-object against the HEAD blob plus a clean git status for both paths.

⚠️ The first attempt of all three read exit 1 everywhere in 17 seconds. That was not a result:
without OS_TEST_TIERS=nightly the package collects none of these files, and it says so
loudly. Recorded here because a run that measured nothing is the failure mode this card is
about. The numbers below are from the re-run with the switch set.

ABL-1 — the #17633 shape, reproduced and then shown fixed. A COMMENT is injected into
src/commands/info.ts between async run( and its first flags.json read, naming
printHeader(. Behaviour is untouched; only prose moved.

leg pin exit reading
masked (this PR) diff-usage-error-stream 0 prose is invisible
raw (pre-conversion, restored from the merge base) same file 1 AssertionError: expected [ 'info.ts' ] to deeply equal []

⭐ That failure line IS the card's first row: a docblock reporting an order change that never
happened.

ABL-2 — serve.ts, both directions.

leg mutation pin exit reading
1 const hostRoot = servedAppRootOrCwd(); becomes process.cwd() converted 1 a host root is bound without resolving through servedAppRootOrCwd(): expected [ Array(1) ] to deeply equal [] — the new partition is not vacuous
2 a THIRD parameter added to importFromHost, same arguments, same behaviour converted 0 the argument LIST is no longer the contract
2 same mutation pre-conversion 1 expected '…' to contain 'function importFromHost(specifier: st…' — #17725 verbatim, on a pin no pull request can see

ABL-3 — the login emitter partition.

leg mutation pin exit reading
1 a real second await emitJson( outside emitRecord converted 1 every --json write in login.ts must go through emitRecord(): expected [ Array(1) ] to deeply equal []
2 a COMMENT quoting emitJson(payload, 0) converted 0 prose is invisible
2 same comment pre-conversion 1 same assertion — a comment breaking a pin whose code never moved, the card's second row

All three restored cleanly: git hash-object matches the HEAD blob for every mutated path and
git status --porcelain is empty for both paths in each script.

Verification

  • ⚠️ Tier. OS_TEST_TIERS unset collects none of these files. Every red/green below is
    under OS_TEST_TIERS=nightly. Independently confirmed by pnpm check:tier-file-adoption:
    68 nightly-tier files on disk, owned by one package.
  • packages/cli built (pnpm --filter '@objectstack/cli...' build) so the pins that refuse
    at load on an absent dist/index.js actually run.
  • Both whole-package runs, no --project filter — what CI runs:
pnpm --filter @objectstack/cli test                       Test Files  267 passed (267)   Tests  3485 passed (3485)   exit 0
OS_TEST_TIERS=nightly pnpm --filter @objectstack/cli test  Test Files   68 passed  (68)   Tests   695 passed  (695)   exit 0

The 12 converted files were also run on their own under OS_TEST_TIERS=nightly before the
whole runs: 12 files / 336 tests / exit 0.

  • Gate families derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack and reconciled with --ran: 47 derived, 46 run green, 1 NOT
    MEASURED
    — pnpm check:dual-build-cjs-loads exits 3 (PREREQUISITE NOT MET: it reads built
    output for packages outside this closure). ⛔ Recorded as NOT MEASURED, not as a pass and not
    as a red.
  • pnpm lint over the whole repo, unnarrowed. node --stack-size=4000 eslint . --no-inline-config over the whole repository, exit 0.
    This is the unnarrowed run, so no narrowing has to be justified.

skip-changeset, by measurement with controls both ways

This PR's own diff (git diff --name-only origin/main...HEAD) is 12 files, all under
packages/cli/test/. packages/cli's files[] is ["dist","README.md","CHANGELOG.md"] and
tsconfig.build.json has include: ["src"], so test/ reaches neither. Measured against the
built tree rather than argued:

  • negative — bodySpan, splitParams, paramsOf (the three symbols this PR introduces):
    0 files in dist, 0 in README.md.
  • positive control — anchorServedApp (2 files), servedAppRootOrCwd (2), emitRecord (3)
    in dist, so the grep over the published tree finds things and the zero above is a reading,
    not a dead search.
  • ⛔ No scripts/** path is touched, so the published surface did not have to be re-derived.

Fences

Acceptance notes

  • src/commands/serve-cluster-host-resolution.test.ts carries a private stripComments at
    line 151. It is a DECLARED row in check-comment-mask-adoption.mjs's shrink-only ledger,
    measured there as agreeing with the shared mask byte for byte over 212 files, so it is
    recorded debt rather than a finding, and converting it is that ledger's per-row work.
    Noted, not filed.
  • validate-json-failure-{warnings,conversions} still pin a multi-line spread ORDER in
    validate.ts byte-exactly (...ruleAdvisories, ...docWarnings, ...), and the two
    build-json-failure-* files pin the same shape over compile.ts. That is a rung-1/rung-2
    question on an axis this PR did not open, and for the build-* pair it sits in the file the
    fence closes. Noted, not filed — the carrier is card [finding] two more nightly-only emitJson exit-count pins freeze 11/10/1 over compile.ts — green today, one honest exit from rerunning the #18848 p1 #18894, which is already open over those
    two files.
  • invocation-loudness.e2e.test.ts and serve-host-fallback-base.e2e.test.ts reach
    ../src/... and are NOT source-text readers (they symlink and execute it). No rung applies;
    recorded so the next re-derivation does not re-open them. Noted, not filed.

Generated by Claude Code

…s own source

WIP: the twelve nightly-tier test files that read `packages/cli`'s own source
text now read it through the shared `maskComments`, and three byte-exact pins
are rewritten to bind a derived property instead of a spelling.

Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3
Co-authored-by: Claude <noreply@anthropic.com>
@os-support-ai os-support-ai added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 18, 2026 — with Claude
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 02bdeaaf23a208d27d9c6490755356f7464c5380 → packageMentionDocs.

@os-support-ai
os-support-ai marked this pull request as ready for review September 18, 2026 06:45
@os-support-ai
os-support-ai added this pull request to the merge queue Sep 18, 2026
Merged via the queue into main with commit f112a74 Sep 18, 2026
40 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-18520-nightly-pin-source-readers branch September 18, 2026 07:03
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
… so an honest new exit cannot red `main` at night (objectstack-ai#18966)

Fixes objectstack-ai#18894

Clause-②: no

## What this changes

`packages/cli/test/build-json-failure-warnings.e2e.test.ts` and
`packages/cli/test/build-json-failure-conversions.e2e.test.ts` each
froze three integers read
off `packages/cli/src/commands/compile.ts` — 11 payload literals, 10
`success: false`,
1 `success: true`. **All six were correct**, and that is the defect: the
*shape*, not a stale
number. One honest new exit — the very thing these two files exist to
enforce — turns all six
red, and because both files are nightly-tier by NAME they turn red only
at night, hours after
the PR that did it has merged. That is objectstack-ai#18848's `priority:p1` pre-staged
on `compile.ts`.

Ported from the shape PR objectstack-ai#18880 landed on the sibling
`validate-json-failure-*` pair:

- the count is **derived** — `toHaveLength(callSites.length)` against a
word-boundary
`emitJson` call-site match over **the same masked source** the payload
extractor reads;
- the old integer is demoted to a **floor**,
`toBeGreaterThanOrEqual(10)`, which rots only in
  the exits-are-REMOVED direction;
- one **partition** assertion (`success: true` ×1, `success: false` =
`literals.length - 1`)
  replaces the two frozen counts.

⛔ No production file is touched. The diff is those two test files and
nothing else —
`compile.ts` is card objectstack-ai#18431's carrier (branch `ccdc9f5389`) and is left
alone.

## Premises, re-measured on `origin/main` before a line was written

Re-derived with the tests' OWN extractor against the masked `compile.ts`
at
`f112a740bd` (`origin/main` at branch point), ⛔ not inherited from the
card:

```
payload literals          11      the pins' 11 was correct
success: false            10      correct
success: true              1      correct
/\bemitJson\s*\(/g        11      symmetric with the extractor
```

**Collection, re-measured in this worktree** (`vitest list --filesOnly`,
`packages/cli`):
`OS_TEST_TIERS` unset ⇒ 267 files, **0** of these two among them, lit
control
`artifact-packages.test.ts` present; `=nightly` ⇒ 68 files, **both**
present, lit control
absent. Both files sit in the `integration` project (`--project unit`
collects 0 of them).

## ⚠️ The trap this card names — the verdict key, MEASURED not copied

**`compile.ts` spells its verdict key `success:`. `validate.ts` spells
it `valid:`.** Measured
over the 11 masked payload literals of `compile.ts`:

| needle | count |
|:--|--:|
| `success: false` | 10 |
| `success: true` | 1 |
| `valid: false` | **0** |
| `valid: true` | **0** |

A verbatim port of objectstack-ai#18880's two partition lines would have asserted over
an **empty
population**. The lines here read `success:`, and the reading is
recorded in the code comment
beside them so the next author does not have to re-derive it.

## The symmetry the derived form needs — every `emitJson` occurrence
enumerated

The looser `/\bemitJson\s*\(/g` can only be trusted equal to the
extractor's
`await emitJson(` needle if nothing else in the file matches it.
Enumerated with left context
on `compile.ts`, **13 raw occurrences**:

| where | reading |
|:--|:--|
| `:43` | `emitJson,` — an **import** from `../utils/format.js`. No
paren ⇒ matches neither side. |
| `:104`, `:694` | prose inside comments — the shared `maskComments`
blanks both (objectstack-ai#18520, applied to these two files by objectstack-ai#18924) |
| the other 10 | `await emitJson(` call sites, plus the multi-line ones
⇒ 11 payload literals |

⭐ `emitJson` is **IMPORTED here, never declared** — there is no
`function emitJson(` in
`compile.ts` (grep: zero hits for `function emitJson` / `const
emitJson`), so the looser
pattern cannot over-count and red the pin by construction. Raw and
masked agree: 11 literals,
11 call sites, both ways. That agreement is a **reading, not a law**,
and the derived equality
is exactly where a future file that broke it would report.

## The floor's anchor — 10, and why not 11

objectstack-ai#18880 chose "the population the governing ruling was made over", not
today's count. The
equivalent anchor here is the commit that landed each file's ruling,
read out of git:

| file | ruling | landed by | count pinned that day |
|:--|:--|:--|--:|
| `build-json-failure-warnings.e2e.test.ts` | maintainer, 2026-08-25,
option 1 (objectstack-ai#11772) | `d114d5e140` (objectstack-ai#12079) | `toHaveLength(10)` — 9
failure + 1 success |
| `build-json-failure-conversions.e2e.test.ts` | the same 2026-08-25
ruling applied to `conversions` (objectstack-ai#12125) | `79cf692b0e` (objectstack-ai#12285) |
`toHaveLength(10)` — "all nine of its failure exits" + 1 |

Control for the anchor rule: the sibling
`validate-json-failure-warnings.e2e.test.ts` was
created at `33e81a5fe0` (objectstack-ai#12130) pinning `toHaveLength(6)`, and objectstack-ai#18880's
floor is `6`. Same
rule, same arithmetic. ⇒ **the floor here is 10.** Today's eleventh exit
is ADR-0130 D4's
per-package author-time rule leg (objectstack-ai#14439), which arrived *after* the
ruling — exactly what a
derived count absorbs and a frozen one trips over.

## Ablation battery — every leg's mutation proven on disk, every restore
proven by hash

Harness: a bash trap on EXIT, INT and TERM whose handler is the restore
function, absolute paths, restore is
`git checkout HEAD -- PATH` (never a bare `git checkout --`), verified
by comparing
`git hash-object` against the HEAD blob hash **and** by `git diff HEAD`
being empty. Each leg
prints the extractor's counts BEFORE and AFTER the mutation and a marker
grep, so a no-op leg
is refused rather than read as green. All runs `OS_TEST_TIERS=nightly`,
exit codes captured
before any pipe. No rebuild is needed or done: both files read
`compile.ts` from disk and the
CLI is loaded from `src/` through `bin/run-dev.js`, as each file's own
header states.

| leg | mutation to `compile.ts` | measured on disk after | THIS branch
| the frozen `11/10/1` |
|:--|:--|:--|:--|:--|
| 0 control | none | literals 11 · sites 11 | **GREEN** 7/7 | — |
| A | honest 12th exit carrying **both** keys | literals 12 · sites 12 |
**GREEN** 7/7 | **RED** — `expected [ …(12) ] to have a length of 11`
(both files) |
| B | 12th exit **missing** both keys | literals 12 · sites 12 | **RED**
— `an os build --json exit publishes no warnings` / `no conversions` | —
|
| C | 12th call site spelled **without `await`** | literals 11 · sites
**12** | **RED** — `an emitJson( call site the payload extractor could
not read: expected [ …(11) ] to have a length of 12` | **GREEN** 7/7 |
| D | two exits deleted (truncation) | literals 9 · sites 9 | **RED** —
`publishes fewer exits than the ruling above was made over: expected 9
to be greater than or equal to 10` | — |

⭐ **Leg C is the one that decides it.** A twelfth call site the payload
extractor cannot read
leaves the frozen integer **green** and reddens the derived equality.
The frozen form is not a
parallel option — it is strictly weaker. Leg A is the mirror: the honest
exit this contract
exists to welcome now stays green instead of reddening `main` at 20:44Z.

The "old" arms of A and C ran the pre-change files restored
worktree-only with
`git restore --source=f112a740bd -- PATH`, hashes printed and matched
against the BASE blobs,
then reset with `git checkout HEAD -- PATH`.

## `skip-changeset`, by measurement with controls both ways

`packages/cli` `files[]` is `["dist","README.md","CHANGELOG.md"]`;
`tsconfig.build.json` has
`rootDir: "src"`, `include: ["src"]` and an `exclude` that drops every
`*.test.ts`. Measured
against the freshly built `packages/cli/dist`:

| probe | direction | hits in `dist/` |
|:--|:--|--:|
| `an emitJson( call site the payload extractor could not read` | new,
this diff | **0** |
| `publishes fewer exits than the ruling above was made over` | new,
this diff | **0** |
| `ABLATION` | new, this diff | **0** |
| `access matrix drift` | positive control, lives in
`src/commands/compile.ts` | 1 |
| `warningsSoFar` | positive control | 2 |
| `runtime bundle failed` | positive control | 1 |
| `build-json-failure` | ⚠️ 1 hit — `dist/commands/compile.js:621`, a
**comment** compiled from `src/commands/compile.ts:698` that names the
test file. Not this diff's content; `compile.ts` is untouched. | 1 |

The positive controls prove the grep was reading `dist`. Nothing this
diff adds reaches any
published path from any released package ⇒ `skip-changeset`, label
applied on this PR.

## ⚠️ The adjacent axis — a POSITION, not a silent widening

Comment 5726117707 on the card asked for a judgement on the byte-exact
multi-line spread ORDER
pin, and warned its own probe was narrow. **Re-derived here with a
different predicate**
(`expect(SRC)` / `SRC.match` / `SRC.indexOf` across all four files),
which finds MORE than the
seat's word probe did — including one in
`validate-json-failure-conversions.e2e.test.ts`, where
the seat's probe scored 0 and recorded it as **未判**:

| file | line | what it binds byte-exactly |
|:--|--:|:--|
| `build-json-failure-warnings.e2e.test.ts` | `:536` `:537` | `const
warningsSoFar = () => [` , and the 4-member spread ORDER |
| `build-json-failure-conversions.e2e.test.ts` | `:450` | sink
declaration + blank line + `try {` adjacency |
| `validate-json-failure-warnings.e2e.test.ts` | `:571` `:572` | the
same two, 5 members |
| `validate-json-failure-conversions.e2e.test.ts` | `:486` | the same
adjacency ⇐ **the seat's 0 was 未判, not absent** |

**Judgement: named, measured, and left to the seat — deliberately NOT
done in this PR.**
Against the lane's standing three-rung ruling (claim 5725386686 on
objectstack-ai#18520):

- **Rung 1** — 「⛔ nightly-only 的 pin 永不绑一个逐 PR 兄弟已经绑着的字节精确拼写。」 Its
precondition is measured **FALSE**. Repo-wide, the only other reader of
those four list
identifiers is `build-json-advisory-parity.e2e.test.ts`, which is itself
**nightly-tier**
and compares with `new Set(...)` — order-blind by construction. No
per-PR sibling binds this
order behaviourally or textually. ⇒ rung 1 does not authorise deleting
it.
- **Rung 2** — 「⭐ nightly-only 的 pin 绑那条性质本身,从源码推导 —— 读出来的计数、分区、下限
—— ⛔ 永不绑一个写死的数。」 It governs frozen **numbers**. The order pin binds a
*spelling*.
⇒ rung 2 does not reach it; this PR discharges rung 2 for the counts,
which is this card.
- **Rung 3** — 「⭐ 一个读原始源码文本的读者,要么能把代码和散文分开,要么就不该对位置/顺序下
断言。」 Already satisfied: PR objectstack-ai#18924 put the shared `maskComments` in place
on both files. ⛔
  Not re-added here.

⇒ Under the ruling **as written and as measured**, the order pin in
these two files is
currently compliant and needs no change. What is *not* settled is a
rung-1 **extension**: may a
nightly-only pin bind a byte-exact spelling when **no** per-PR sibling
binds the property at
all? That is a new question, not an application of the existing three
rungs, and it sits
identically on the `validate-json-failure-*` pair, **which has no
carrier card**. Widening this
PR to answer it would convert half a family under a rule nobody has made
yet. Handed to the
`domain:cli` seat as a finding with dedupe words.

## Verification

Measured on `git rev-parse --short HEAD` = `0eb90c0a91`, in worktree
`/home/user/objectstack-issue-18894`, branched from `origin/main` at
`f112a740bd`.

| what | how | result |
|:--|:--|:--|
| the two files, BEFORE the edit | `OS_TEST_TIERS=nightly … --project
integration` on both files | **27 passed (27)** — the pins were correct,
as the card said |
| the two files, AFTER the edit | same | **27 passed (27)** |
| `packages/cli` WHOLE, default tier | `pnpm --filter @objectstack/cli
test` (bare `vitest run`, ⛔ no `--project`) | **267 files / 3485 tests
passed** |
| `packages/cli` WHOLE, nightly tier | `OS_TEST_TIERS=nightly pnpm
--filter @objectstack/cli test` | **68 files / 695 tests passed** — the
tier that actually collects these two files |
| typecheck | `pnpm --filter @objectstack/cli typecheck` | exit 0 (incl.
`check:test-typecheck`) |
| dependency closure + package build | `pnpm --filter
'@objectstack/cli^...' build` then `pnpm --filter @objectstack/cli
build` | exit 0 both — required, several pins refuse at load without it
|
| gate families | `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`, then `--ran` with exit codes | 47 derived,
**46 run green**, **1 NOT MEASURED** |
| whole-repo lint | `pnpm lint` (`eslint . --no-inline-config`), NOT
narrowed | exit 0 |

**NOT MEASURED (1)**: `pnpm check:dual-build-cjs-loads` exits **3** —
`PREREQUISITE NOT MET —
this gate reads built output, and some package has no dist/`. It needs a
whole-repo `pnpm
build`; this worktree built only the `@objectstack/cli` closure. ⛔
Recorded as NOT MEASURED,
not as a pass and not as a red. CI's `Build Core` job builds the tree
and measures it there.
`dispatch-gates --ran` classified it from the recorded exit code rather
than from a claim.

Two derivation caveats stated rather than hidden: `dispatch-gates`
printed a **STALE TREE**
warning (`origin/main` moved 2 commits under this branch, touching
`scripts/check-adr-0087-registration.mjs` and
`scripts/check-single-claim-paths.mjs`); the
command list was re-derived after `git fetch origin main` and came back
**byte-identical**, so
the 47 stands. And the tool's own footer is quoted rather than
paraphrased: the 47 is not a
complete account of CI — 51 artifact-roster families, 11 wide-population
families, 13
pending-changeset families and 5 path-scheduled CI jobs are outside it
by construction.

## Acceptance notes

Noted, not filed — observations from the two files, none of them a
reproducible defect, a
contract violation, or a metadata-authoring trap:

- The `describe` blocks in both files are still titled with their
originating card numbers
(`objectstack-ai#11772`, `objectstack-ai#12125`) while the assertions inside them now answer objectstack-ai#18894
too. Cosmetic;
renaming a `describe` moves every `-t` filter that names it. Carrier:
whoever next opens
  these files for a behavioural change.
- `packages/cli/test/build-json-advisory-parity.e2e.test.ts` is
nightly-tier and is the only
other reader of the four advisory-list identifiers; its `new Set(...)`
comparisons are
deliberately order-blind, so the family has **no** order coverage in the
per-PR tier at all.
Recorded as the measurement behind the adjacent-axis position above, not
as a defect.
Carrier: the `domain:cli` seat, together with the rung-1 extension
question.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3)_

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

2 participants